package com.ndp.fb.walle.business.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Joiner;
import com.ndp.fb.config.ConfigCentre;
import com.ndp.fb.constant.CommonConstants;
import com.ndp.fb.constant.ConfigConst;
import com.ndp.fb.enums.Status;
import com.ndp.fb.enums.TagForBuildnameType;
import com.ndp.fb.enums.adresource.AdCreativeType;
import com.ndp.fb.enums.publish.AdObjective;
import com.ndp.fb.enums.publish.BillingEvent;
import com.ndp.fb.enums.publish.OptimizationGoal;
import com.ndp.fb.enums.publish.PublishStatus;
import com.ndp.fb.enums.targetingspec.Connections;
import com.ndp.fb.enums.targetingspec.Gender;
import com.ndp.fb.enums.targetingspec.PageType;
import com.ndp.fb.enums.targetingspec.UserOs;
import com.ndp.fb.exception.AdsetLimitException;
import com.ndp.fb.exception.BusinessException;
import com.ndp.fb.exception.ErrorCode;
import com.ndp.fb.model.DateModel;
import com.ndp.fb.model.business.bo.image.AdImageBo;
import com.ndp.fb.model.business.bo.result.RegionAndPriceBo;
import com.ndp.fb.model.business.bo.result.RegionBo;
import com.ndp.fb.model.business.bo.targetingspec.*;
import com.ndp.fb.model.business.bo.useraudience.result.LocalTargetingSpecs;
import com.ndp.fb.model.business.bo.useraudience.result.TargetingSpecBo;
import com.ndp.fb.model.business.bo.useraudience.result.TargetingSpecGroupBo;
import com.ndp.fb.model.business.vo.advertising.param.AdImageVoParam;
import com.ndp.fb.model.business.vo.advertising.param.AdVideoVoParam;
import com.ndp.fb.model.business.vo.advertising.param.BidInfoVoParam;
import com.ndp.fb.model.business.vo.cache.param.Schedule;
import com.ndp.fb.model.business.vo.cache.result.*;
import com.ndp.fb.model.fbagent.param.adcreative.*;
import com.ndp.fb.mongo.api.AdVideoMongoService;
import com.ndp.fb.mongo.api.PublishCacheMongoService;
import com.ndp.fb.mongo.model.AdvideoForMongo;
import com.ndp.fb.rdb.api.*;
import com.ndp.fb.rdb.model.*;
import com.ndp.fb.redis.api.RedisClient;
import com.ndp.fb.redis.model.*;
import com.ndp.fb.util.*;
import com.ndp.fb.walle.business.PublishCacheService;
import com.ndp.fb.walle.model.bo.publishbatch.result.ScheduleBo;
import com.ndp.fb.walle.model.bo.publishbatchactionrecord.param.PublishBatchActionTargetingBo;
import com.ndp.fb.walle.model.vo.entrustaccount.param.EntrustAccountParam;
import com.ndp.fb.walle.util.BuildCacheUtils;
import com.ndp.fb.walle.util.ConversionUtils;
import com.ndp.fb.walle.util.ResponseUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.ndp.fb.model.business.vo.cache.result.ChooseType.CAROUSEL;
import static com.ndp.fb.model.business.vo.cache.result.ChooseType.VIDEO;

/**
 * Created by Administrator on 2014/12/24.
 */
@Component
public class PublishCacheServiceImpl implements PublishCacheService {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Reference
    private PublishBatchRdbService publishBatchRdbService;

    @Reference
    private UserAudienceRdbService userAudienceRdbService;

    @Reference
    private TargetingSpecGroupRdbService targetingSpecGroupRdbService;

    @Reference
    private TargetingSpecRdbService targetingSpecRdbService;
    @Reference
    private AdVideoMongoService adVideoMongoService;

    @Reference
    private PublishResultRdbService publishResultRdbService;


    @Reference
    private PublishCacheMongoService publishCacheMongoService;

    @Autowired
    private RedisClient redisClient;

    @Reference
    private PublishBatchActionRecordRdbService publishBatchActionRecordRdbService;

    /**
     * 给fb放的地址
     */
    private String NFS_CONFIG_FB_VISIT_DOMAIN = ConfigCentre.getString(ConfigConst.NFS_CONFIG_FB_VISIT_DOMAIN);
    private String NFS_CONFIG_DOMAIN = ConfigCentre.getString(ConfigConst.NFS_CONFIG_DOMAIN);

    @Override
    public String publish(PublishCache cache) throws BusinessException, AdsetLimitException {
        //1、accounts
        List<EntrustAccountParam> accounts = prcessAccountInfo(cache);
        if (ListUtil.isNotEmpty(accounts)) {
            boolean isNeedRecord = false;
            if (ConfigCentre.getBoolean(ConfigConst.NEED_PUBLISHBATCHACTIONRECORD)) {
                isNeedRecord = true;
            }
            List<PublishResult> publishResults = new ArrayList<>();
            List<Long> delpublishResultsForAudience = new ArrayList<>();
            PublishResult publishResult;

            //遍历发布地区子批次
            List<GeoSubPublishBatchCache> geoSubPublishBatches = cache.getGeoSubPublishBatchs();
            for (GeoSubPublishBatchCache geoSubPublishBatch : geoSubPublishBatches) {
                cache.setBatchIndex(geoSubPublishBatch.getIndex());
                List<BidInfoVoParam> bidInfos = geoSubPublishBatch.getBidInfos();
                //验证当前批次中是否只有CPA出价方式，且所有账号都不支持CPA的情况
                int b = 0;
                int c = 0;
                for (EntrustAccountParam account : accounts) {
                    for (BidInfoVoParam bidInfo : bidInfos) {
//                        if (bidInfo == null || ("CPA".equals(bidInfo.getBidType()))) {
                        if (bidInfo == null || bidInfo.getBillingEvent().equals(BillingEvent.APP_INSTALLS.getCode())) {
                            b++;
                            if (account.getIsSupportCPA() != 1) {
                                b--;
                            }
                        } else {
                            c++;
                        }
                    }
                }
                if (c == 0 && b == 0) {
                    continue;
                }

                //2、save批次信息，并且将生成的用户定位Id存入PublishBatch
                //保存缓存之前，将状态设为4，前置全部处理完再进入发布流程
                savePublishBatch(cache, bidInfos);

                /**
                 * 保存批次行为记录 add by Sisi
                 * @modify by Evan  操作记录，BI组需要再打开
                 */
                if (isNeedRecord) {
                    //TODO 行为记录
                    savePublishBatchActionRecord(cache);
                }

                //3、保存结果
                publishResults.clear();
                for (EntrustAccountParam account : accounts) {
                    publishResult = new PublishResult();
                    publishResult.setBatchId(cache.getPublishBatchId());
                    publishResult.setAccountId(account.getAccountId());
                    publishResult.setAccountEmail(account.getEmail());
                    publishResults.add(publishResult);
                }
                List<Long> resultIds = publishResultRdbService.batchSave(publishResults);

                for (int i = 0; i < accounts.size(); i++) {
                    accounts.get(i).setResultId(resultIds.get(i));
                }

                //4、构造cacheList
                try {
                    AdPublishCache adPublishCache = buildAdPublishCache(cache, accounts, geoSubPublishBatch);
                    //5.保存用户定位信息,将生成的用户定位Id入缓存
                    saveUserAudience(cache);
                    //6、缓存消息
                    adPublishCache.setCacheId("batchId_" + cache.getPublishBatchId());
                    saveCacheToMongo(cache.getPublishBatchId(),adPublishCache);
                    //cache直接存入mongo中 后面改
                    //Client.set("batchId_" + cache.getPublishBatchId(), adPublishCache, 24L, TimeUnit.HOURS.name());
                    // 更新结果信息
                    publishResults.clear();
                    for (EntrustAccountParam account : accounts) {
                        publishResult = new PublishResult();
                        publishResult.setPublishResultId(account.getResultId());
                        publishResult.setAdcreativeCount(account.getAdCreativeBuildCount());
                        publishResult.setAdcampaignCount(account.getAdCampaignBuildCount());
                        publishResult.setAdsetCount(account.getAdSetBuildCount());
                        publishResult.setAdgroupCount(account.getAdGroupBuildCount());
                        publishResults.add(publishResult);
                    }
                    publishResultRdbService.batchUpdatePublishResultCount(publishResults);
                    if(adPublishCache.getAdCampaignGroupLevelMap().size() == 0)
                    {
                        publishBatchRdbService.deleteByBatchId(cache.getPublishBatchId());
                    }
                    else
                    {
                        //7、更新批次状态为0，以及数量int account_count, int campaign_count, int adset_count, int adgroup_count, int creative_count
                        publishBatchRdbService.updatePublishBathById(cache.getPublishBatchId(), PublishStatus.WAIT_PRE_PROCESS.getCode(), cache.getUserAudienceId(),
                                accounts.size(),
                                adPublishCache.getAdCampaignGroupLevelMap().size(),
                                adPublishCache.getAdSetLevelMap().size(),
                                adPublishCache.getAdGroupLevelMap().size(),
                                adPublishCache.getAdCreativeLevelMap().size());
                    }
                } catch (Exception e) {
                    publishBatchRdbService.deleteByBatchId(cache.getPublishBatchId());
                    logger.info("PublishCacheServiceImpl publish() error:" + e.getMessage());
                    throw e;
                }
            }
            return "success";
        } else {
            return "No accounts";
        }
    }

    private void saveCacheToMongo(Long publishBatchId,AdPublishCache adPublishCache) {
        ThreadPool.execute(() -> {
            try {
                publishCacheMongoService.save(JSONObject.toJSONString(adPublishCache, SerializerFeature.DisableCircularReferenceDetect));
            }catch (Exception e){
                logger.error(e.getMessage(),e);
                //fail over , if save to mongo exception, save as to redis
                redisClient.set("batchId_" + publishBatchId, adPublishCache, 24L, TimeUnit.HOURS.name());
            }

        });
    }

    private void savePublishBatchActionRecord(PublishCache cache) {
        PublishBatchActionRecord publishBatchActionRecord = new PublishBatchActionRecord();
        publishBatchActionRecord.setUserId(cache.getUserId());
        publishBatchActionRecord.setPublishBatchId(cache.getPublishBatchId());
        publishBatchActionRecord.setProductConfId(cache.getProductConfiguration().getId());
        publishBatchActionRecord.setPublishBatchName(cache.getPublishBatchFinishName());
        publishBatchActionRecord.setConnectionObjectName(cache.getConnectionObject().getName());
        publishBatchActionRecord.setConfiguration(cache.getProductConfiguration().getPlatform());
        publishBatchActionRecord.setAdwords(buildAdWords(cache.getAdWords()));

        if (!CollectionUtils.isEmpty(cache.getAdImages())) {
            //设置图片
            List<AdImageVoParam> adImagesCache = cache.getAdImages();
            publishBatchActionRecord.setImages(JSONArray.toJSONString(adImagesCache));
            List<String> imagesShow = new ArrayList<>();

            for (AdImageVoParam adImageVoParam : adImagesCache) {
                imagesShow.add(CommonConstants.SYMBOL_DOUBLE_QUOTATION
                        + adImageVoParam.getMd5()
                        + CommonConstants.SYMBOL_LINE + "(" + adImageVoParam.getCount() + ")"
                        + CommonConstants.SYMBOL_DOUBLE_QUOTATION);
            }
            publishBatchActionRecord.setImagesShow(imagesShow.toString());
        }
        if (!CollectionUtils.isEmpty(cache.getAdVideos())) {
            //设置视频
            List<AdVideoVoParam> adVideoCache = cache.getAdVideos();
            publishBatchActionRecord.setImages(JSONArray.toJSONString(adVideoCache));
            List<String> imagesShow = new ArrayList<>();

            for (AdVideoVoParam adVideoVoParam : adVideoCache) {
                imagesShow.add(CommonConstants.SYMBOL_DOUBLE_QUOTATION
                        + adVideoVoParam.getMongoId()
                        + CommonConstants.SYMBOL_LINE + "(" + adVideoVoParam.getCount() + ")"
                        + CommonConstants.SYMBOL_DOUBLE_QUOTATION);
            }
            publishBatchActionRecord.setImagesShow(imagesShow.toString());
        }


        //设置用户定位相关信息
        setTargetingSpecsInfo(publishBatchActionRecord, cache.getUserAudience().getPublishingTargetingSpecGroups());

        Date date = new Date();
        publishBatchActionRecord.setCreateTime(date);
        publishBatchActionRecord.setCreateUtcTime(date.getTime());

        publishBatchActionRecordRdbService.savePublishBatchActionRecord(publishBatchActionRecord);
    }

    private String buildAdWords(List<String> adWords) {
        List<String> showAdWords = new ArrayList<String>();
        for (String adWord : adWords) {
            showAdWords.add("\"" + adWord.replace("\"", "\\") + "\"");
        }

        return showAdWords.toString();
    }

    private void setTargetingSpecsInfo(PublishBatchActionRecord publishBatchActionRecord,
                                       List<TargetingSpecGroupBo> publishingTargetingSpecGroups) {
        PublishBatchActionTargetingBo publishBatchActionTargetingBo
                = buildTargetingSpecConditionsByResult(publishingTargetingSpecGroups);

        if (null != publishBatchActionTargetingBo.getPlatform()) {
            publishBatchActionRecord.setPlatform(publishBatchActionTargetingBo.getPlatform().toString());
        }

        if (null != publishBatchActionTargetingBo.getUserOsShow()) {
            publishBatchActionRecord.setUserOsShow(publishBatchActionTargetingBo.getUserOsShow());
        }

        if (null != publishBatchActionTargetingBo.getUserDeviceShow()) {
            publishBatchActionRecord.setUserDeviceShow(publishBatchActionTargetingBo.getUserDeviceShow());
        }

        if (null != publishBatchActionTargetingBo.getPageTypes()) {
            publishBatchActionRecord.setPageTypes(publishBatchActionTargetingBo.getPageTypes().toString());
        }

        if (null != publishBatchActionTargetingBo.getPageTypesShow()) {
            publishBatchActionRecord.setPageTypesShow(publishBatchActionTargetingBo.getPageTypesShow().toString());
        }

        if (null != publishBatchActionTargetingBo.getLocations()) {
            publishBatchActionRecord.setLocations(publishBatchActionTargetingBo.getLocations().toString());
        }

        if (null != publishBatchActionTargetingBo.getShowLocations()) {
            publishBatchActionRecord.setLocationsShow(publishBatchActionTargetingBo.getShowLocations().toString());
        }

        if (null != publishBatchActionTargetingBo.getAges()) {
            publishBatchActionRecord.setAges(publishBatchActionTargetingBo.getAges().toString());
        }

        if (null != publishBatchActionTargetingBo.getShowAges()) {
            publishBatchActionRecord.setAgesShow(publishBatchActionTargetingBo.getShowAges().toString());
        }

        if (null != publishBatchActionTargetingBo.getGenders()) {
            publishBatchActionRecord.setGenders(publishBatchActionTargetingBo.getGenders().toString());
        }

        if (null != publishBatchActionTargetingBo.getShowGenders()) {
            publishBatchActionRecord.setGendersShow(publishBatchActionTargetingBo.getShowGenders().toString());
        }

        if (null != publishBatchActionTargetingBo.getInterests()) {
            publishBatchActionRecord.setInterests(publishBatchActionTargetingBo.getInterests().toString());
        }

        if (null != publishBatchActionTargetingBo.getShowInterests()) {
            publishBatchActionRecord.setInterestsShow(publishBatchActionTargetingBo.getShowInterests().toString());
        }


        if (null != publishBatchActionTargetingBo.getConnections()) {
            publishBatchActionRecord.setConnections(publishBatchActionTargetingBo.getConnections().toString());
        }

        if (null != publishBatchActionTargetingBo.getConnectionsShow()) {
            publishBatchActionRecord.setConnectionsShow(publishBatchActionTargetingBo.getConnectionsShow().toString());
        }
    }

    private PublishBatchActionTargetingBo buildTargetingSpecConditionsByResult(List<TargetingSpecGroupBo> targetingSpecGroups) {
        LocalTargetingSpecs localTargetingSpecs;
        PublishBatchActionTargetingBo publishBatchActionRecordParam = new PublishBatchActionTargetingBo();

        for (TargetingSpecGroupBo targetingSpecGroup : targetingSpecGroups) {
            localTargetingSpecs = targetingSpecGroup.getLocalTargetingSpecs();
            //平台相关信息
            buildPlatForms(publishBatchActionRecordParam.getPlatFormGroups(),
                    publishBatchActionRecordParam, localTargetingSpecs.getPlatform());

            //版位
            buildPageTypes(publishBatchActionRecordParam.getPageTypeGroups(),
                    publishBatchActionRecordParam.getPageTypes(),
                    publishBatchActionRecordParam.getPageTypesShow(), localTargetingSpecs.getPageTypes());

            //地区
            buildLocations(publishBatchActionRecordParam.getLocationGroups(),
                    publishBatchActionRecordParam.getLocations(),
                    publishBatchActionRecordParam.getShowLocations(), localTargetingSpecs.getLocalLocation());

            //年龄
            buildAges(publishBatchActionRecordParam.getAgeGroups(), publishBatchActionRecordParam.getAges(),
                    publishBatchActionRecordParam.getShowAges(), localTargetingSpecs.getAge());

            //性别
            buildGenders(publishBatchActionRecordParam.getGenderGroups(), publishBatchActionRecordParam.getGenders(),
                    publishBatchActionRecordParam.getShowGenders(), localTargetingSpecs.getGenders());

            //兴趣
            buildInterests(publishBatchActionRecordParam.getInterestGroups(), publishBatchActionRecordParam.getInterests(),
                    publishBatchActionRecordParam.getShowInterests(), localTargetingSpecs.getInterests());

            //联系
            buildConnections(publishBatchActionRecordParam.getConnectionsGroups(),
                    publishBatchActionRecordParam, localTargetingSpecs.getLocalConnection());
        }

        return publishBatchActionRecordParam;
    }

    private void buildPlatForms(List<Long> platFormGroups,
                                PublishBatchActionTargetingBo publishBatchActionRecord, Platform platform) {
        if (null == platform) {
            return;
        }

        //如果相应组已在条件中
        if (platFormGroups.contains(platform.getIndex())) {
            return;
        }
        platFormGroups.add(platform.getIndex());

        publishBatchActionRecord.setPlatform(platform);
        String userOs = buildUserOs(platform);
        publishBatchActionRecord.setUserOsShow(userOs);
        String userDevice = buildUserDevice(platform);
        publishBatchActionRecord.setUserDeviceShow(userDevice);
    }

    private void buildConnections(List<Long> connectionsGroups,
                                  PublishBatchActionTargetingBo publishBatchActionRecord, LocalConnection localConnection) {
        if (null == localConnection) {
            return;
        }

        //如果相应组已在条件中
        if (connectionsGroups.contains(localConnection.getIndex())) {
            return;
        }
        connectionsGroups.add(localConnection.getIndex());

        publishBatchActionRecord.setConnections(localConnection);

        //构造显示connections
        FacebookConnection facebookConnection = localConnection.getConnections().get(0);
        StringBuilder interestsSb = new StringBuilder();
        Connections connections = Connections.getConnections(localConnection.getType());
        if (Connections.Connections == connections) {
            //Only people connected to Fantasy Of Elements
            interestsSb.append("Only people connected to " + facebookConnection.getName());
        } else if (Connections.Excluded_connections == connections) {
            //Only people not connected to Fantasy Of Elements
            interestsSb.append("Only people not connected to " + facebookConnection.getName());
        } else {
            interestsSb.append("All");
        }
        publishBatchActionRecord.setConnectionsShow(interestsSb.toString());
    }

    private void buildInterests(List<Long> interestGroups, List<List<Interest>> interests,
                                List<String> showInterests, LocalInterest localInterest) {
        if (null == localInterest) {
            return;
        }
        //如果相应组已在条件中
        if (interestGroups.contains(localInterest.getIndex())) {
            return;
        }
        interestGroups.add(localInterest.getIndex());

        List<Interest> singleInterests = localInterest.getInterests();
        interests.add(singleInterests);

        //构造显示interest
        //无interest即全部
        if (ListUtil.isEmpty(singleInterests)) {
            showInterests.add("\"All\"");
            return;
        }

        StringBuilder interestsSb = new StringBuilder();
        boolean isFirst = true;
        interestsSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        for (Interest interest : singleInterests) {
            if (!isFirst) {
                interestsSb.append(CommonConstants.SYMBOL_COMMA);
            }
            isFirst = false;
            interestsSb.append(interest.getName().replace("\"", "\\\""));
        }
        interestsSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        showInterests.add(interestsSb.toString());
    }

    private void buildGenders(List<Long> genderGroups, List<List<Integer>> genders,
                              List<String> showGenders, LocalGender localGender) {
        if (null == localGender) {
            return;
        }
        //如果相应组已在条件中
        if (genderGroups.contains(localGender.getIndex())) {
            return;
        }
        genderGroups.add(localGender.getIndex());

        List<Integer> singleGenders = localGender.getGenders();
        genders.add(singleGenders);

        //无性别即全部
        //构造显示gender
        if (ListUtil.isEmpty(singleGenders)) {
            showGenders.add("\"All\"");
            return;
        }

        StringBuilder genderSb = new StringBuilder();
        boolean isFirst = true;
        genderSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        for (Integer gender : singleGenders) {
            if (!isFirst) {
                genderSb.append(CommonConstants.SYMBOL_COMMA);
            }
            isFirst = false;
            genderSb.append(Gender.getGender(gender).getGender());
        }
        genderSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        showGenders.add(genderSb.toString());
    }

    private void buildAges(List<Long> ageGroups, List<Age> ages, List<String> showAges, Age age) {
        if (null == age) {
            return;
        }

        //如果相应组已在条件中
        if (ageGroups.contains(age.getIndex())) {
            return;
        }
        ageGroups.add(age.getIndex());

        ages.add(age);

        //构造显示age
        Integer ageMin = age.getAgeMin();
        Integer ageMax = age.getAgeMax();

        StringBuilder ageSb = new StringBuilder();
        ageSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        ageSb.append(ageMin);


        //如果年龄上限等于年龄下限，则显示年龄下限即可
        BuildCacheUtils.ageAppend(ageMin, ageMax, ageSb);
        ageSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        showAges.add(ageSb.toString());
    }

    private void buildLocations(List<Long> locationGroups, List<LocalLocation> locations,
                                List<String> showLocations, LocalLocation localLocation) {
        if (null == localLocation) {
            return;
        }

        //如果相应组已在条件中
        if (locationGroups.contains(localLocation.getIndex())) {
            return;
        }
        locationGroups.add(localLocation.getIndex());

        locations.add(localLocation);

        //构造显示location
        //未选择地区即全部
        if (ListUtil.isEmpty(localLocation.getCountries())
                && ListUtil.isEmpty(localLocation.getCities())) {
            showLocations.add("\"All\"");
            return;
        }

        StringBuilder locationSb = new StringBuilder();
        boolean isFirst = true;
        locationSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        List<Country> countries = localLocation.getCountries();
        if (!ListUtil.isEmpty(countries)) {
            for (Country country : countries) {
                if (!isFirst) {
                    locationSb.append(CommonConstants.SYMBOL_COMMA);
                }
                isFirst = false;
                locationSb.append(country.getName().replace("\"", "\\\"") + "(country)");
            }
        }

        List<City> cities = localLocation.getCities();
        if (!ListUtil.isEmpty(cities)) {
            for (City city : cities) {
                if (!isFirst) {
                    locationSb.append(CommonConstants.SYMBOL_COMMA);
                }
                isFirst = false;
                locationSb.append(city.getName().replace("\"", "\\\"") + "(city)");
            }
        }
        locationSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        showLocations.add(locationSb.toString());

    }

    private void buildPageTypes(List<Long> pageTypeGroups, List<List<Integer>> pageTypes,
                                List<String> showPageTypes, LocalPageType localPageType) {
        if (null == localPageType || ListUtil.isEmpty(localPageType.getPageTypes())) {
            return;
        }

        //如果相应组已在条件中
        if (pageTypeGroups.contains(localPageType.getIndex())) {
            return;
        }
        pageTypeGroups.add(localPageType.getIndex());

        List<Integer> singlePageTypes = localPageType.getPageTypes();
        pageTypes.add(singlePageTypes);

        //构造显示PageType
        if (ListUtil.isEmpty(singlePageTypes)) {
            showPageTypes.add("\"All\"");
            return;
        }

        boolean isFirst = true;
        StringBuilder pageTypeSb = new StringBuilder();
        pageTypeSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        BuildCacheUtils.pageAppend(singlePageTypes, isFirst, pageTypeSb);
        pageTypeSb.append(CommonConstants.SYMBOL_DOUBLE_QUOTATION);
        showPageTypes.add(pageTypeSb.toString());
    }



    private String buildUserDevice(Platform platform) {
        if (null == platform || org.springframework.util.CollectionUtils.isEmpty(platform.getUserDevice())) {
            return null;
        }
        List<String> userDevices = platform.getUserDevice();
        StringBuilder userDevicesSb = new StringBuilder();
        boolean isFirst = true;
        BuildCacheUtils.userDeviceAppend(userDevices, userDevicesSb, isFirst);
        return userDevicesSb.toString();
    }


    private String buildUserOs(Platform platform) {
        if (null == platform || null == platform.getType() || org.springframework.util.CollectionUtils.isEmpty(platform.getUserOS())) {
            return null;
        }

        Integer type = platform.getType();
        String osPrefix;
        String osPostfix = ResponseUtils.getMsgByKey("WALLE_OSPOSTFIX");
        if (UserOs.iOS.getCode() == type) {
            //IOS
            osPrefix = "iOS" + ResponseUtils.getMsgByKey("WALLE_VERSION");

        } else {
            //Android
            osPrefix = "android" + ResponseUtils.getMsgByKey("WALLE_VERSION");
        }

        List<String> userOSs = platform.getUserOS();
        StringBuilder userOSsSb = new StringBuilder();
        boolean isFirst = true;
        BuildCacheUtils.userOSAppend(osPrefix, osPostfix, userOSs, userOSsSb, isFirst);
        return userOSsSb.toString();
    }



    private void savePublishBatch(PublishCache cache, List<BidInfoVoParam> bidInfos) {
        //CacheGeoLocationVoParam cacheGeoLocationVoParam = cache.getUserAudience().getLongCacheGeoLocationVoParamMap().get(cache.getBatchIndex());
        PublishBatch publishBatch = new PublishBatch();
        String batchName = buildBatchName(cache);
        publishBatch.setUserId(cache.getUserId());
        publishBatch.setProductConfId(cache.getProductConfiguration().getId());
        publishBatch.setConfiguration(cache.getProductConfiguration().getPlatform());
        publishBatch.setConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());//Evan 2014-12-09 向批次增加属性connectionObjectId
        publishBatch.setConnectionObjectName(cache.getConnectionObject().getName());
        publishBatch.setImageInfo(JSON.toJSONString(cache.getAdImages()));
        if (ListUtil.isNotEmpty(cache.getAdImages())) {
            publishBatch.setImageInfo(JSON.toJSONString(cache.getAdImages()));
        } else {
            publishBatch.setImageInfo(JSON.toJSONString(cache.getAdVideos()));
        }
        publishBatch.setBidInfo(JSON.toJSONString(bidInfos));
        publishBatch.setCreateTime(new Date());
        publishBatch.setCustomMessage(cache.getCustomMessage());
        publishBatch.setTimezone(cache.getTimeZone());
        Schedule schedule = cache.getSchedule();
        //delete by sisi 预算出价优化后  预算与出价相对应  即一个批次内有多个预算
//        publishBatch.setDailyBudget(cacheGeoLocationVoParam.getDailyBudget());
//        publishBatch.setLifetimeBudget(cacheGeoLocationVoParam.getLifetimeBudget());
        publishBatch.setStartTime(schedule.getStartTimeDate());
        publishBatch.setStartUtcTime(schedule.getStartUTCTime());
        publishBatch.setEndTime(schedule.getEndTimeDate());
        publishBatch.setEndUtcTime(schedule.getEndUTCTime());
        publishBatch.setIsControl(false);
        publishBatch.setPublishBatchName(batchName);
        publishBatch.setCpa(cache.getCpa());
        publishBatch.setUserAudienceId(-1L);
        //保存缓存之前，将状态设为4，避免Quartz创建AdCreative时，批次已经入库但是缓存还未入
        publishBatch.setPublishStatus(PublishStatus.ASSEMBLY.getCode());
        publishBatch.setContinueTime((new Date().getTime() - cache.getBeginTime()) / 1000);
        cache.setPublishBatchId(publishBatchRdbService.save(publishBatch));
        cache.setPublishBatchFinishName(batchName);
    }

    private synchronized String buildBatchName(PublishCache cache) {
        return cache.getNickName()+CommonConstants.SYMBOL_UNDERLINE + getDateModel(new Date(), "yyyyMMdd_HHmmss", cache.getTimeZone());
    }

    public static String getDateModel(Date date, String format, String timeZone) {
        Calendar time = Calendar.getInstance();
        time.setTime(date);
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        if(null != timeZone) {
            dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
        }
        return dateFormat.format(Long.valueOf(date.getTime()));
    }

    private void saveUserAudience(PublishCache cache) {
        UserAudience userAudience = new UserAudience();
        userAudience.setName(cache.getPublishBatchFinishName());
        userAudience.setFbConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());
        userAudience.setUserId(cache.getUserId());
        Long userAudienceId = userAudienceRdbService.save(userAudience);
        cache.setUserAudienceId(userAudienceId);

        TargetingSpecGroup targetingSpecGroup = new TargetingSpecGroup();
        targetingSpecGroup.setUserAudienceId(userAudienceId);
        Long targetingSpecGroupId = targetingSpecGroupRdbService.save(targetingSpecGroup);

        List<TargetingSpec> targetingSpecList = new ArrayList<>();
        TargetingSpec targetingSpec;
        for (TargetingSpecGroupBo targetingSpecGroups : cache.getUserAudience().getPublishingTargetingSpecGroups()) {
            for (TargetingSpecBo targetingSpecs : targetingSpecGroups.getTargetingSpecBoes()) {
                targetingSpec = new TargetingSpec();
                targetingSpec.setSpec(targetingSpecs.getSpec());
                targetingSpec.setType(targetingSpecs.getType().getIndex());
                targetingSpec.setTargetingSpecGroupId(targetingSpecGroupId);
                targetingSpecList.add(targetingSpec);
            }
        }
        if (ListUtil.isNotEmpty(targetingSpecList)) {
            targetingSpecRdbService.save(targetingSpecList);
        }
        //cache.setUserAudienceId(userAudienceId);
    }

    private List<EntrustAccountParam> prcessAccountInfo(PublishCache cache) {
        List<EntrustAccountParam> accountParamList = new ArrayList<>();
        EntrustAccountParam entrustAccountParam;
        String accountInfo = cache.getAccountsInfo();
        String[] accountIds = accountInfo.split(",");
        for (EntrustAccountVo account : cache.getEntrustAccounts()) {
            for (int i = 0; accountIds.length > i; i++) {
                if ((account.getFbAccountId() + "").equals(accountIds[i])) {
                    entrustAccountParam = new EntrustAccountParam();
                    entrustAccountParam.setAccessToken(cache.getFbUserVo().getAccessToken());
                    entrustAccountParam.setEmail(account.getDisplayName());
                    entrustAccountParam.setAccountId("act_" + account.getFbAccountId());
                    entrustAccountParam.setTimeZone(account.getTimezone());
                    entrustAccountParam.setIsSupportCPA(account.getIsSupportCPA());
                    entrustAccountParam.setAdCampaignCount(account.getAdCampaignCount());
                    entrustAccountParam.setAdSetCount(account.getAdSetCount());
                    entrustAccountParam.setAdGroupCount(account.getAdGroupCount());
                    entrustAccountParam.setIsSupportInstagramAd(account.isSupportInstagramAd());
                    entrustAccountParam.setFirstSupportInsAct(account.getFirstSupportInsAct());
                    accountParamList.add(entrustAccountParam);
                }
            }
        }
        return accountParamList;
    }

    private String getFBVisitPath(String visitPath) {
        logger.info("NFS_CONFIG_DOMAIN>>>>"+ NFS_CONFIG_DOMAIN + " >>>> NFS_CONFIG_FB_VISIT_DOMAIN >>>"+NFS_CONFIG_FB_VISIT_DOMAIN);
        if (StringUtils.isNoneBlank(NFS_CONFIG_FB_VISIT_DOMAIN)) {
            return visitPath.replaceAll(NFS_CONFIG_DOMAIN, NFS_CONFIG_FB_VISIT_DOMAIN);
        } else {
            return visitPath;
        }
    }

    private String getLiteTitle(String liteTitle, String adTitle) {
        if (StringUtil.isEmpty(liteTitle)) {
            //当小标题不存在，则用大标题
            return adTitle;
        } else {
            return liteTitle;
        }
    }

    /**
     * 创建即将发布的批次广告 缓存AdPublishCache
     */
    private AdPublishCache buildAdPublishCache(PublishCache cache, List<EntrustAccountParam> accounts,
                                              GeoSubPublishBatchCache geoSubPublishBatch) throws AdsetLimitException, BusinessException {
        AdPublishCache adPublishCache = new AdPublishCache();
        List<BidInfoVoParam> bidInfos = geoSubPublishBatch.getBidInfos();
        List<TargetingSpecGroupBo> targetingSpecGroups = geoSubPublishBatch.getTargetingSpecGroups();
        if(ListUtil.isEmpty(bidInfos))
        {
            logger.error("PublishCacheServiceImpl publish>>>>>>出价信息是空的");
            return adPublishCache;
        }
        if(ListUtil.isEmpty(targetingSpecGroups))
        {
            logger.error("PublishCacheServiceImpl publish>>>>>>用户定位是空的");
            return adPublishCache;
        }
        //生成广告的链接，主要是为了外链产品
        buildWAdLink(cache);
        //生成创意这一步 正交数
        int creativeCnt = buildCreativeCnt(cache);
        //四个cache里的 容器
        Map<String, AdCreativeLevel> adCreativeLevelMap = new HashMap<>();
        Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap = new HashMap<>();
        Map<String, AdSetLevel> adSetLevelMap = new HashMap<>();
        Map<String, AdGroupLevel> adGroupLevelMap = new HashMap<>();

        CallToActionValue callToActionValue = new CallToActionValue();
        callToActionValue.setLink(cache.getLink());
        CallToAction callToAction = new CallToAction();
        Schedule schedule = cache.getSchedule();
        AtomicInteger thisBatchAdCampaignIndex = new AtomicInteger(1);
        List<String> adGroupKeys = new ArrayList<>();
        List<String> adSetKeys = new ArrayList<>();
        //传递创意用于生成 素材名称
        List<AdCreativeLevel> adCreativeLevels = new ArrayList<>();
        for (EntrustAccountParam account : accounts) {
            AtomicInteger adCampaignIndex = new AtomicInteger(1);
            AtomicInteger adSetIndex = new AtomicInteger(1);
            AtomicInteger adGroupIndex = new AtomicInteger(1);
            AtomicInteger adGroupAbsIndex = new AtomicInteger(1);
            AtomicInteger adSetAbsIndex = new AtomicInteger(1);

            //一个批次支持多种出价方式
            for (BidInfoVoParam bidInfo : bidInfos) {
                //出价勾选了CPA 又不支持的
                if (bidInfo == null
                        || (bidInfo.getBillingEvent().equals(BillingEvent.APP_INSTALLS.getCode())&&account.getIsSupportCPA()!=1)) {
                    logger.error("PublishCacheServiceImpl publish>>>>>> 广告账号{}不支持计费方式：APP_INSTALLS。",account.getAccountId());
                    continue;
                }

                //自定义出价方式:名称自定义中的出价方式
                String cBidType = customBidType(bidInfo);
                //根据预算类型以及账号时区处理排程
                ScheduleBo scheduleBo = preProcessSchedule(schedule, cache.getTimeZone(), account.getTimeZone(), bidInfo.getBudgetType());

                for (TargetingSpecGroupBo specGroup : targetingSpecGroups) {
                    //Instagram广告需求判断用户定位版位 带 ins的  然后这个账号又不支持 ，则pass
                    if(specGroup.getTargetingSpecs().indexOf(PageType.instagramstream.getPageTypeName()) > -1 && !account.isSupportInstagramAd())
                        continue;
                    /**
                     * 现需求：选了某账号自定义受众 生成的 用户定位组必然全都是包含自定义受众条件的
                     * 1、用户定位组 含有 自定义受众的 只会按 账户 -> 含有该账户用户定位->生成广告、广告系列、营销活动
                     * 2、用户定位组 不含有 自定义受众的 则按之前的流程发广告
                     */
                    Set<String> adCountryKeys = new LinkedHashSet<>();
                    Set<String> adGenderKeys = new LinkedHashSet<>();
                    Set<String> adAgeKeys = new LinkedHashSet<>();
                    Set<String> locationKeys = new LinkedHashSet<>();
                    String targetJson = specGroup.getTargetingSpecs();
                    adCountryKeys.addAll(buildCountryDescription(specGroup.getLocalTargetingSpecs().getLocalLocation()));
                    adGenderKeys.addAll(buildGenderDescription(specGroup.getLocalTargetingSpecs().getGenders()));
                    adAgeKeys.addAll(buildAgeDescription(specGroup.getLocalTargetingSpecs().getAge()));
                    locationKeys.addAll(buildLocationKeys(specGroup.getLocalTargetingSpecs().getLocalLocation()));
                    if (specGroup.getLocalTargetingSpecs().getFbAccountId() != null ) {
                        if (account.getAccountId().equals("act_" + specGroup.getLocalTargetingSpecs().getFbAccountId().toString())) {
                            logger.info("--------" + account.getAccountId() + "generateSuccess，含自定义受众" + specGroup.getLocalTargetingSpecs().getFbAccountId() + "用户定位匹配了账户。");
                            buildLevel(cache, bidInfos, targetingSpecGroups, creativeCnt, adCreativeLevelMap,
                                    adCampaignGroupLevelMap, adSetLevelMap, adGroupLevelMap, callToActionValue, callToAction,
                                    thisBatchAdCampaignIndex, adGroupKeys, adSetKeys, adCreativeLevels, account, adCampaignIndex,
                                    adSetIndex, adGroupIndex, adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, specGroup,
                                    adCountryKeys, adGenderKeys, adAgeKeys, locationKeys, targetJson);
                        }
                    } else {
                        logger.info("--------" + account.getAccountId() + "generateOld用户定位条件不含自定义受众-----------");
                        buildLevel(cache, bidInfos, targetingSpecGroups, creativeCnt, adCreativeLevelMap, adCampaignGroupLevelMap,
                                adSetLevelMap, adGroupLevelMap, callToActionValue, callToAction, thisBatchAdCampaignIndex, adGroupKeys,
                                adSetKeys, adCreativeLevels, account, adCampaignIndex, adSetIndex, adGroupIndex, adGroupAbsIndex, adSetAbsIndex,
                                bidInfo, cBidType, scheduleBo, specGroup, adCountryKeys, adGenderKeys, adAgeKeys, locationKeys, targetJson);
                    }
                }
            }
            checkUltralimit(account, adCampaignIndex, adGroupAbsIndex, adSetAbsIndex);
        }

        adPublishCache.setAdCampaignGroupLevelMap(adCampaignGroupLevelMap);
        adPublishCache.setAdSetLevelMap(adSetLevelMap);
        adPublishCache.setAdGroupLevelMap(adGroupLevelMap);
        adPublishCache.setAdCreativeLevelMap(adCreativeLevelMap);
        return adPublishCache;
    }

    private void buildLevel(PublishCache cache, List<BidInfoVoParam> bidInfos, List<TargetingSpecGroupBo> targetingSpecGroups, int creativeCnt, Map<String, AdCreativeLevel> adCreativeLevelMap, Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap, Map<String, AdSetLevel> adSetLevelMap, Map<String, AdGroupLevel> adGroupLevelMap, CallToActionValue callToActionValue, CallToAction callToAction, AtomicInteger thisBatchAdCampaignIndex, List<String> adGroupKeys, List<String> adSetKeys, List<AdCreativeLevel> adCreativeLevels, EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adSetIndex, AtomicInteger adGroupIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex, BidInfoVoParam bidInfo, String cBidType, ScheduleBo scheduleBo, TargetingSpecGroupBo specGroup, Set<String> adCountryKeys, Set<String> adGenderKeys, Set<String> adAgeKeys, Set<String> locationKeys, String targetJson) throws AdsetLimitException, BusinessException {
        for (String adWord : cache.getAdWords()) {
            switch (cache.getChooseType()) {
                case IMG:  //图片广告
                    buildImage(cache, bidInfos, targetingSpecGroups, creativeCnt, adCreativeLevelMap,
                            adCampaignGroupLevelMap, adSetLevelMap, adGroupLevelMap, callToActionValue, callToAction,
                            thisBatchAdCampaignIndex, adGroupKeys, adSetKeys, adCreativeLevels, account, adCampaignIndex,
                            adSetIndex, adGroupIndex, adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, specGroup,
                            adCountryKeys, adGenderKeys, adAgeKeys, locationKeys, targetJson, adWord);
                    break;
                case VIDEO:   //视频广告
                    buildVideo(cache, bidInfos, targetingSpecGroups, creativeCnt, adCreativeLevelMap,
                            adCampaignGroupLevelMap, adSetLevelMap, adGroupLevelMap, callToActionValue, callToAction,
                            thisBatchAdCampaignIndex, adGroupKeys, adSetKeys, adCreativeLevels, account, adCampaignIndex,
                            adSetIndex, adGroupIndex, adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, specGroup,
                            adCountryKeys, adGenderKeys, adAgeKeys, locationKeys, targetJson, adWord);
                    break;
                case CAROUSEL:  //轮播广告
                    buildCarousel(cache, bidInfos, targetingSpecGroups, creativeCnt, adCreativeLevelMap,
                            adCampaignGroupLevelMap, adSetLevelMap, adGroupLevelMap, callToActionValue, callToAction,
                            thisBatchAdCampaignIndex, adGroupKeys, adSetKeys, adCreativeLevels, account, adCampaignIndex,
                            adSetIndex, adGroupIndex, adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, adCountryKeys,
                            adGenderKeys, adAgeKeys, locationKeys, targetJson, adWord);
                    break;
                default:
                    throw new BusinessException("没有选择素材");
            }
        }
    }

    private void buildImage(PublishCache cache, List<BidInfoVoParam> bidInfos, List<TargetingSpecGroupBo> targetingSpecGroups, int creativeCnt, Map<String, AdCreativeLevel> adCreativeLevelMap, Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap, Map<String, AdSetLevel> adSetLevelMap, Map<String, AdGroupLevel> adGroupLevelMap, CallToActionValue callToActionValue, CallToAction callToAction, AtomicInteger thisBatchAdCampaignIndex, List<String> adGroupKeys, List<String> adSetKeys, List<AdCreativeLevel> adCreativeLevels, EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adSetIndex, AtomicInteger adGroupIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex, BidInfoVoParam bidInfo, String cBidType, ScheduleBo scheduleBo, TargetingSpecGroupBo specGroup, Set<String> adCountryKeys, Set<String> adGenderKeys, Set<String> adAgeKeys, Set<String> locationKeys, String targetJson, String adWord) throws AdsetLimitException {
        if (!StringUtils.equals(CommonConstants.OUTLINK, cache.getConnectionObject().getProductType())) {
            callToActionValue.setLinkTitle(cache.getAdTitle());
        }

        callToAction.setType(cache.getCallToActionType().getType());
        callToAction.setValue(callToActionValue);

        for (AdImageVoParam adImageVoParam : cache.getAdImages()) {
            // 图片被选择的次数
            int imageCount = adImageVoParam.getCount();
            for (int i = 0; i < imageCount; i++) {
                // 一 1）、生成创意
               String adCreativeKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adCreative_" + adGroupAbsIndex;
                AdCreativeLevel adCreativeLevel = new AdCreativeLevel();
                ObjectStorySpec objectStorySpec = new ObjectStorySpec();
                objectStorySpec.setPageId(cache.getPage().getFbPageId() + "");
                if (account.isSupportInstagramAd() && specGroup.getTargetingSpecs().indexOf(PageType.instagramstream.getPageTypeName()) > -1)
                    objectStorySpec.setInstagramActorId(account.getFirstSupportInsAct());
                LinkData linkData = new LinkData();
                //Modify By Sisi 图片直接用url
                // linkData.setImageHash(imageHash);
                linkData.setPictureName(adImageVoParam.getName());
                linkData.setPicture(getFBVisitPath(adImageVoParam.getVisitPath()));
                if (CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
                    linkData.setName(cache.getAdTitle());
                    linkData.setDescription(cache.getWAdDesc());
                    linkData.setCaption(cache.getWAdCaption());
                }

                linkData.setLink(cache.getLink());
                linkData.setMessage(adWord);
                linkData.setCallToAction(callToAction);
                objectStorySpec.setLinkData(linkData);
                adCreativeLevel.setImageMd5(adImageVoParam.getMd5());
                adCreativeLevel.setType(AdCreativeType.ADIMAGE.getType());
                buildAdCreativeLevel(cache, adCreativeLevelMap, adCreativeLevel, adCreativeKey, account, objectStorySpec);
                // 一 2）、生成adgroup
                String adGroupKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adGroup_" + adGroupAbsIndex;
                AdGroupLevel  adGroupLevel = new AdGroupLevel();
                generateAdGroupLevel(adCreativeLevel, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, adGroupLevel, cache, account,
                        targetJson, adGroupIndex.intValue(), thisBatchAdCampaignIndex.intValue(), adSetIndex.intValue(), adGroupKey);
                adGroupLevelMap.put(adGroupKey, adGroupLevel);
                adGroupKeys.add(adGroupKey);
                adCreativeLevels.add(adCreativeLevel);
                buildAdsetAndCampagin(cache, bidInfos, targetingSpecGroups, creativeCnt,
                        adCampaignGroupLevelMap, adSetLevelMap, thisBatchAdCampaignIndex, adGroupKeys,
                        adSetKeys, adCreativeLevels, account, adCampaignIndex, adSetIndex, adGroupIndex,
                        adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, adCountryKeys, adGenderKeys,
                        adAgeKeys, locationKeys, targetJson);
                adGroupIndex.incrementAndGet();
                adGroupAbsIndex.incrementAndGet();
            }
        }
    }

    private void buildVideo(PublishCache cache, List<BidInfoVoParam> bidInfos, List<TargetingSpecGroupBo> targetingSpecGroups, int creativeCnt, Map<String, AdCreativeLevel> adCreativeLevelMap, Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap, Map<String, AdSetLevel> adSetLevelMap, Map<String, AdGroupLevel> adGroupLevelMap, CallToActionValue callToActionValue, CallToAction callToAction, AtomicInteger thisBatchAdCampaignIndex, List<String> adGroupKeys, List<String> adSetKeys, List<AdCreativeLevel> adCreativeLevels, EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adSetIndex, AtomicInteger adGroupIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex, BidInfoVoParam bidInfo, String cBidType, ScheduleBo scheduleBo, TargetingSpecGroupBo specGroup, Set<String> adCountryKeys, Set<String> adGenderKeys, Set<String> adAgeKeys, Set<String> locationKeys, String targetJson, String adWord) throws AdsetLimitException {
        if (CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
            callToActionValue.setLinkCaption(cache.getWAdCaption());
            callToActionValue.setLinkDescription(cache.getWAdDesc());
        }

        callToActionValue.setLinkTitle(cache.getAdTitle());
        callToAction.setType(cache.getCallToActionType().getType());
        callToAction.setValue(callToActionValue);
        VideoData videoData;
        for (AdVideoVoParam adVideoVoParam : cache.getAdVideos()) {
            AdvideoForMongo adVideo = adVideoMongoService.findByMongoId(adVideoVoParam.getMongoId());
            //视频缩略图
            List<AdImageVoParam> adImages = adVideoVoParam.getAdImages();
            for (AdImageVoParam adImageVoParam : adImages) {
                int imageCount = adImageVoParam.getCount();
                for (int j = 0; j < imageCount; j++) {
                    //视频+缩略图+广告词  构成创意
                    String adCreativeKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adCreative_" + adGroupAbsIndex;
                    AdCreativeLevel   adCreativeLevel = new AdCreativeLevel();
                    ObjectStorySpec objectStorySpec = new ObjectStorySpec();
                    objectStorySpec.setPageId(String.valueOf(cache.getPage().getFbPageId()));
                    if (account.isSupportInstagramAd() && specGroup.getTargetingSpecs().indexOf(PageType.instagramstream.getPageTypeName()) > -1)
                        objectStorySpec.setInstagramActorId(account.getFirstSupportInsAct());
                    videoData = new VideoData();
                    videoData.setVideoId(null);
                    videoData.setMongoId(adVideo.getMongodbId());
                    videoData.setMd5(adVideo.getMd5());
                    videoData.setTitle(cache.getConnectionObject().getName());
                    videoData.setDescription(adWord);
                    videoData.setCallToAction(callToAction);
                    //Modify By Sisi 图片用url
                    videoData.setImageUrl(getFBVisitPath(adImageVoParam.getVisitPath()));

                    videoData.setPictureName(adVideoVoParam.getName());
                    objectStorySpec.setVideoData(videoData);
                    adCreativeLevel.setImageMd5(adImageVoParam.getMd5());
                    adCreativeLevel.setVideoMd5(adVideo.getMd5());
                    adCreativeLevel.setType(AdCreativeType.ADVIDEO.getType());
                    buildAdCreativeLevel(cache, adCreativeLevelMap, adCreativeLevel, adCreativeKey, account, objectStorySpec);
                    String adGroupKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adGroup_" + adGroupAbsIndex;
                    AdGroupLevel  adGroupLevel = new AdGroupLevel();
                    generateAdGroupLevel(adCreativeLevel, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, adGroupLevel, cache, account,
                            targetJson, adGroupIndex.intValue(), thisBatchAdCampaignIndex.intValue(), adSetIndex.intValue(), adGroupKey);
                    adGroupLevelMap.put(adGroupKey, adGroupLevel);
                    adGroupKeys.add(adGroupKey);
                    adCreativeLevels.add(adCreativeLevel);
                    buildAdsetAndCampagin(cache, bidInfos, targetingSpecGroups, creativeCnt,
                            adCampaignGroupLevelMap, adSetLevelMap, thisBatchAdCampaignIndex, adGroupKeys,
                            adSetKeys, adCreativeLevels, account, adCampaignIndex, adSetIndex, adGroupIndex,
                            adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, adCountryKeys, adGenderKeys,
                            adAgeKeys, locationKeys, targetJson);
                    adGroupIndex.incrementAndGet();
                    adGroupAbsIndex.incrementAndGet();
                }
            }
        }
    }

    private void buildCarousel(PublishCache cache, List<BidInfoVoParam> bidInfos, List<TargetingSpecGroupBo> targetingSpecGroups, int creativeCnt, Map<String, AdCreativeLevel> adCreativeLevelMap, Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap, Map<String, AdSetLevel> adSetLevelMap, Map<String, AdGroupLevel> adGroupLevelMap, CallToActionValue callToActionValue, CallToAction callToAction, AtomicInteger thisBatchAdCampaignIndex, List<String> adGroupKeys, List<String> adSetKeys, List<AdCreativeLevel> adCreativeLevels, EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adSetIndex, AtomicInteger adGroupIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex, BidInfoVoParam bidInfo, String cBidType, ScheduleBo scheduleBo, Set<String> adCountryKeys, Set<String> adGenderKeys, Set<String> adAgeKeys, Set<String> locationKeys, String targetJson, String adWord) throws AdsetLimitException {
        // 总的行动号召
        callToActionValue.setLinkTitle(cache.getAdTitle());
        callToAction.setType(cache.getCallToActionType().getType());
        callToAction.setValue(callToActionValue);
        String liteTitle;
        AdImageBo imageInfo;
        List<AdImageBo> imageInfoes;
        CallToActionValue liteCallToActionValue;
        CallToAction liteCallToAction;
        for (List<AdImageVoParam> adImageVoParams : cache.getAdImagesGroup()) {
            //构造创建AdCreatives
            String adCreativeKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adCreative_" + adGroupAbsIndex;
            AdCreativeLevel adCreativeLevel = new AdCreativeLevel();
            ObjectStorySpec objectStorySpec = new ObjectStorySpec();
            objectStorySpec.setPageId(cache.getPage().getFbPageId() + "");
            LinkData linkData = new LinkData();
            List<ChildAttachments> childAttachmentses = new ArrayList<>();
            ChildAttachments childAttachments;
            StringBuffer visitPathSb = new StringBuffer();
            imageInfoes = new ArrayList<>();
            int imageSize = adImageVoParams.size();
            for (int i = 0; i < imageSize; i++) {
                AdImageVoParam adImageVoParam = adImageVoParams.get(i);
                //获取轮播图片小标题
                liteTitle = getLiteTitle(adImageVoParam.getLiteTitle(), cache.getAdTitle());

                String childVisitPath = getFBVisitPath(adImageVoParam.getVisitPath());
                visitPathSb.append(childVisitPath);
                if (i != imageSize - 1) {
                    visitPathSb.append(",");
                }

                imageInfo = new AdImageBo();
                imageInfo.setVisitPath(childVisitPath);
                imageInfo.setLiteTitle(liteTitle);
                imageInfoes.add(imageInfo);

                childAttachments = new ChildAttachments();
                childAttachments.setLink(cache.getLink());
                childAttachments.setPicture(childVisitPath);
                childAttachments.setName(liteTitle);

                //每个轮播图都有自己的行动号召
                liteCallToActionValue = new CallToActionValue();
                liteCallToActionValue.setLink(cache.getLink());
                liteCallToActionValue.setLinkTitle(liteTitle);
                liteCallToAction = new CallToAction();
                liteCallToAction.setType(cache.getCallToActionType().getType());
                liteCallToAction.setValue(liteCallToActionValue);
                childAttachments.setCallToAction(liteCallToAction);

                if (StringUtils.equals(CommonConstants.OUTLINK, cache.getConnectionObject().getProductType())) {
                    //外链子项支持 说明
                    childAttachments.setDescription(cache.getWAdDesc());
                }

                childAttachments.setImgName(adImageVoParam.getName());
                childAttachmentses.add(childAttachments);
            }

            if (CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
                linkData.setCaption(cache.getWAdCaption());
            }

            linkData.setLink(cache.getLink());
            linkData.setMessage(adWord);
            linkData.setChildAttachmentses(childAttachmentses);
            linkData.setMultiShareOptimized(false);
            linkData.setCallToAction(callToAction);
            objectStorySpec.setLinkData(linkData);
            adCreativeLevel.setType(AdCreativeType.ADCAROUSEL.getType());
            buildAdCreativeLevel(cache, adCreativeLevelMap, adCreativeLevel, adCreativeKey, account, objectStorySpec);
            String adGroupKey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adGroup_" + adGroupAbsIndex;
            AdGroupLevel adGroupLevel = new AdGroupLevel();
            generateAdGroupLevel(adCreativeLevel, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, adGroupLevel, cache, account,
                    targetJson, adGroupIndex.intValue(), thisBatchAdCampaignIndex.intValue(), adSetIndex.intValue(), adGroupKey);
            adGroupLevelMap.put(adGroupKey, adGroupLevel);
            adGroupKeys.add(adGroupKey);
            adCreativeLevels.add(adCreativeLevel);
            buildAdsetAndCampagin(cache, bidInfos, targetingSpecGroups, creativeCnt,
                    adCampaignGroupLevelMap, adSetLevelMap, thisBatchAdCampaignIndex, adGroupKeys,
                    adSetKeys, adCreativeLevels, account, adCampaignIndex, adSetIndex, adGroupIndex,
                    adGroupAbsIndex, adSetAbsIndex, bidInfo, cBidType, scheduleBo, adCountryKeys, adGenderKeys,
                    adAgeKeys, locationKeys, targetJson);
            adGroupIndex.incrementAndGet();
            adGroupAbsIndex.incrementAndGet();
        }
    }

    private void checkUltralimit(EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex) throws AdsetLimitException {
        //一个批次最多发10000个campaign add by evan 20151201  晓剑需求
        if (adCampaignIndex.intValue() > 10000) {
            throw new AdsetLimitException(ErrorCode.ERROR_60020);
        }
        //判断营销活动数量是否超限
        if (adCampaignIndex.intValue() > account.getAdCampaignCount()) {
            String message = "The batch a account (" + account.getAccountId() + ") has reached the maximum amount of ad campaign ";
            logger.error(message);
            throw new AdsetLimitException(message);
        }
        //判断adset数量是否超限
        else if(adSetAbsIndex.intValue() > account.getAdSetCount()){
            String message = "The batch a account ("+account.getAccountId()+") has reached the maximum amount of ad sets ";
            logger.error(message);
            throw new AdsetLimitException(message);
        } else if (adGroupAbsIndex.intValue() > account.getAdGroupCount()) {
            String message = "The batch a account (" + account.getAccountId() + ") has reached the maximum amount of ads ";
            logger.error(message);
            throw new AdsetLimitException(message);
        } else {
            account.setAdCampaignBuildCount(adCampaignIndex.intValue() - 1);
            account.setAdSetBuildCount(adSetAbsIndex.intValue() - 1);
            account.setAdGroupBuildCount(adGroupAbsIndex.intValue() - 1);
            account.setAdCreativeBuildCount(adGroupAbsIndex.intValue() - 1);
        }
    }

    private void buildAdsetAndCampagin(PublishCache cache, List<BidInfoVoParam> bidInfos, List<TargetingSpecGroupBo> targetingSpecGroups, int creativeCnt, Map<String, AdCampaignGroupLevel> adCampaignGroupLevelMap, Map<String, AdSetLevel> adSetLevelMap, AtomicInteger thisBatchAdCampaignIndex, List<String> adGroupKeys, List<String> adSetKeys, List<AdCreativeLevel> adCreativeLevels, EntrustAccountParam account, AtomicInteger adCampaignIndex, AtomicInteger adSetIndex, AtomicInteger adGroupIndex, AtomicInteger adGroupAbsIndex, AtomicInteger adSetAbsIndex, BidInfoVoParam bidInfo, String cBidType, ScheduleBo scheduleBo, Set<String> adCountryKeys, Set<String> adGenderKeys, Set<String> adAgeKeys, Set<String> locationKeys, String targetJson) throws AdsetLimitException {
        if (adGroupIndex.intValue() == cache.getRatio()
                || (bidInfos.size() * targetingSpecGroups.size() * creativeCnt) == adGroupAbsIndex.intValue()
                || adGroupAbsIndex.intValue() % creativeCnt== 0) {
            // 二、生成adset
            AdSetLevel  adSetLevel = new AdSetLevel();
            String adSetkey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adSet_" + adSetAbsIndex;
            generateAdSetLevel(adSetLevel, adCreativeLevels, cache, account, adCountryKeys,
                    adGenderKeys, adAgeKeys, adGroupKeys, bidInfo,cBidType,targetJson,
                    scheduleBo.getEndTimeDateModel(), scheduleBo.getStartTimeDateModel(), adSetkey, locationKeys, adSetIndex.intValue(), thisBatchAdCampaignIndex.intValue());
            // adsetlist key 还未设置
            adSetLevelMap.put(adSetkey, adSetLevel);
            adSetKeys.add(adSetkey);

            // 三、生成adcampaigngroup
            //TODO 1:n:n
            if(adSetIndex.intValue() == 1)
            {
                AdCampaignGroupLevel  adCampaignGroupLevel = new AdCampaignGroupLevel();
                String adCampaignGroupkey = account.getAccountId() + "_" + cache.getPublishBatchId() + "_adCampaignGroup_" + adCampaignIndex;
                generateAdCampaignGroupLevel(adCampaignGroupLevel, adCreativeLevels, cache,
                        account, adCountryKeys, adGenderKeys, adAgeKeys,cBidType, adSetKeys,
                        scheduleBo.getEndTimeDateModel(), scheduleBo.getStartTimeDateModel(), adCampaignGroupkey, locationKeys, thisBatchAdCampaignIndex.intValue());
                // adsetlist key 还未设置
                adCampaignGroupLevelMap.put(adCampaignGroupkey, adCampaignGroupLevel);
                adCampaignIndex.incrementAndGet();
                thisBatchAdCampaignIndex.incrementAndGet();
                adSetIndex = new AtomicInteger(0);
            }

            adGroupKeys.clear();
            adSetKeys.clear();
            adCreativeLevels.clear();
            adSetIndex.incrementAndGet();
            adSetAbsIndex.incrementAndGet();
            adGroupIndex.set(0);
        }
    }

    /**
     * 构建创意level时的公共部分
     * @param cache
     * @param adCreativeLevelMap
     * @param adCreativeLevel
     * @param adCreativeKey
     * @param account
     * @param objectStorySpec
     */
    private void buildAdCreativeLevel(PublishCache cache, Map<String, AdCreativeLevel> adCreativeLevelMap, AdCreativeLevel adCreativeLevel, String adCreativeKey, EntrustAccountParam account, ObjectStorySpec objectStorySpec) {
        adCreativeLevel.setObjectStorySpec(objectStorySpec);
        adCreativeLevel.setUserId(cache.getUserId());
        adCreativeLevel.setCreateTime(cache.getCreateTime());
        adCreativeLevel.setCreateUTCTime(cache.getCreateTime().getTime());
        adCreativeLevel.setUpdateTime(cache.getCreateTime());
        adCreativeLevel.setUpdateUTCTime(cache.getCreateTime().getTime());
        adCreativeLevel.setAccessToken(account.getAccessToken());
        adCreativeLevel.setActAccountId(account.getAccountId());
        adCreativeLevel.setFbConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());
        adCreativeLevel.setFbConnectionObjectName(cache.getConnectionObject().getName());
        adCreativeLevel.setPublishBatchId(cache.getPublishBatchId());
        adCreativeLevel.setPublishBatchName(cache.getPublishBatchFinishName());
        adCreativeLevel.setProductConfigurationId(cache.getProductConfiguration().getId());
        adCreativeLevel.setConfiguration(cache.getProductConfiguration().getPlatform());
        adCreativeLevel.setTimeZone(account.getTimeZone());
        adCreativeLevel.setPublishResultId(account.getResultId());
        adCreativeLevel.setKeyForPublishAd(adCreativeKey);
        adCreativeLevel.setStatus(PublishStatus.WAIT_PUPLISH.getCode());
        adCreativeLevel.setProductType(cache.getConnectionObject().getProductType());
        adCreativeLevelMap.put(adCreativeKey, adCreativeLevel);
    }

    private String customBidType(BidInfoVoParam bidInfo) {
        OptimizationGoal og = OptimizationGoal.parse(bidInfo.getOptimizationGoal());
        BillingEvent be = BillingEvent.parse(bidInfo.getBillingEvent());
        if (OptimizationGoal.LINK_CLICKS == og){
            if (BillingEvent.IMPRESSIONS == be){
                return "OCCPM";
            } else if (BillingEvent.LINK_CLICKS == be){
                return "CPC";
            } else {
                return "undefined";
            }
        } else if (OptimizationGoal.APP_INSTALLS == og){
            if (BillingEvent.IMPRESSIONS == be){
                return "OICPM";
            } else if (BillingEvent.APP_INSTALLS == be){
                return "CPA";
            } else {
                return "undefined";
            }
        } else if (OptimizationGoal.IMPRESSIONS == og){
            if (BillingEvent.IMPRESSIONS == be){
                return "CPM";
            } else {
                return "undefined";
            }
        } else if (OptimizationGoal.REACH == og){
            if (BillingEvent.IMPRESSIONS == be){
                return "ORCPM";
            } else {
                return "undefined";
            }
        } else {
            return "undefined";
        }
    }

    private Set<String> buildLocationKeys(LocalLocation localLocation) {
        List<Country> countries = localLocation.getCountries();
        List<City> cities = localLocation.getCities();
        Set<String> targetingLocations = new HashSet<>();
        if (!CollectionUtils.isEmpty(countries)){
            for (Country country : countries){
                if (null == country.getIsClude() || country.getIsClude()){
                    targetingLocations.add(country.getCountryCode());
                }
            }
        }
        if (!CollectionUtils.isEmpty(cities)){
            for (City city : cities){
                if (null == city.getIsClude() || city.getIsClude()){
                    targetingLocations.add(city.getKey());
                }
            }
        }

        return targetingLocations;
    }

    private ScheduleBo preProcessSchedule(Schedule schedule, String userTimeeZone, String accountTimeZone, Integer budgetType) {
        Date startTimeDate = schedule.getStartTimeDate();
        Date endTimeDate = schedule.getEndTimeDate();

        //当前时间+10min
        long curUtcTime = new Date().getTime() + 600000L;
        long startUtcTime;
        if (null == startTimeDate) {
            startUtcTime = curUtcTime;
        } else {
            startUtcTime = startTimeDate.getTime();
        }
        startUtcTime = startUtcTime > curUtcTime ? startUtcTime : curUtcTime;
        //转成账号时区
        int offset = TimeZone.getTimeZone(accountTimeZone).getRawOffset() / 3600000;
        String strOffset = offset >= 0 ? ("+" + String.format("%02d", offset) + ":00") : (String.format("%03d", offset) + ":00");
        DateModel startTimeDateModel = DateFormatUtil.getDate(new Date(startUtcTime), CommonConstants.DATE_FORMAT_YYYYMMDDHHMMSS, userTimeeZone, accountTimeZone);
        startTimeDateModel.setToTimeString(startTimeDateModel.getToTimeString() + strOffset); //v2.3排程 "2015-03-12 23:59:59-07:00" or "2015-03-12 23:59:59 PDT".

        //当有结束排程时
        DateModel endTimeDateModel = null;
        if (null != endTimeDate) {
            long endUtcTime = endTimeDate.getTime() > curUtcTime ? endTimeDate.getTime() : curUtcTime;
            if (0 == budgetType) {
                if (endUtcTime < startUtcTime + 86401000L) {
                    //日预算在有排程的情况下，必须大于1天
                    endUtcTime = startUtcTime + 86401000L;
                }
            } else {
                if (endUtcTime < startUtcTime + 3600000L) {
                    // 总预算的排程，必须大于1个小时  这个是系统设定的
                    endUtcTime = startUtcTime + 3600000L;
                }
            }

            //转成账号时区
            endTimeDateModel = DateFormatUtil.getDate(new Date(endUtcTime), CommonConstants.DATE_FORMAT_YYYYMMDDHHMMSS, userTimeeZone, accountTimeZone);
            endTimeDateModel.setToTimeString(endTimeDateModel.getToTimeString() + strOffset); //v2.3排程 "2015-03-12 23:59:59-07:00" or "2015-03-12 23:59:59 PDT".
        }

        ScheduleBo scheduleBo = new ScheduleBo();
        scheduleBo.setStartTimeDateModel(startTimeDateModel);
        scheduleBo.setEndTimeDateModel(endTimeDateModel);
        return scheduleBo;
    }

    /**
     * 生成campaign
     */
    private void generateAdCampaignGroupLevel(
            AdCampaignGroupLevel adCampaignGroupLevel, List<AdCreativeLevel> adCreativeLevels, PublishCache cache,
            EntrustAccountParam account, Set<String> adCountryKeys,
            Set<String> adGenderKeys, Set<String> adAgeKeys, String cBidType,
            List<String> adSetKeys, DateModel endTimeDateModel, DateModel startTimeDateModel, String adCampGroupKey, Set<String> locationKeys, int adCampaignIndex) throws AdsetLimitException {
        String name = buildAdName(cache, adCreativeLevels, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, 0, adCampaignIndex, "adCampaignGroup");
        adCampaignGroupLevel.setUserId(cache.getUserId());
        adCampaignGroupLevel.setName(name);
        adCampaignGroupLevel.setCampaignGroupStatus(Status.ACTIVE.getMessageCode());
        adCampaignGroupLevel.setStartTimeString(startTimeDateModel.getToTimeString());
        adCampaignGroupLevel.setStartTime(startTimeDateModel.getDate());
        adCampaignGroupLevel.setStartUTCTime(startTimeDateModel.getUtcTime());
        if (null != endTimeDateModel) {
            adCampaignGroupLevel.setEndTimeString(endTimeDateModel.getToTimeString());
            adCampaignGroupLevel.setEndTime(endTimeDateModel.getDate());
            adCampaignGroupLevel.setEndUTCTime(endTimeDateModel.getUtcTime());
        }
        String objective;
        if (StringUtils.equals(CommonConstants.OUTLINK, cache.getConnectionObject().getProductType())){
            //外链
            objective = AdObjective.LINK_CLICKS.getType();
        } else {
            //应用安装
            objective = AdObjective.MOBILE_APP_INSTALLS.getType();
        }

        adCampaignGroupLevel.setObjective(objective);
        adCampaignGroupLevel.setCreateTime(cache.getCreateTime());
        adCampaignGroupLevel.setCreateUTCTime(cache.getCreateTime().getTime());
        adCampaignGroupLevel.setUpdateTime(cache.getCreateTime());
        adCampaignGroupLevel.setUpdateUTCTime(cache.getCreateTime().getTime());
        adCampaignGroupLevel.setAccessToken(account.getAccessToken());
        adCampaignGroupLevel.setActAccountId(account.getAccountId());
        adCampaignGroupLevel.setFbConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());
        adCampaignGroupLevel.setFbConnectionObjectName(cache.getConnectionObject().getName());
        adCampaignGroupLevel.setPublishBatchId(cache.getPublishBatchId());
        adCampaignGroupLevel.setPublishBatchName(cache.getPublishBatchFinishName());
        adCampaignGroupLevel.setProductConfigurationId(cache.getProductConfiguration().getId());
        adCampaignGroupLevel.setConfiguration(cache.getProductConfiguration().getPlatform());
        adCampaignGroupLevel.setTimeZone(account.getTimeZone());
        adCampaignGroupLevel.setPublishResultId(account.getResultId());
        adCampaignGroupLevel.setStatus(PublishStatus.WAIT_PUPLISH.getCode());
        adCampaignGroupLevel.setAdSetBatchIndexs(BuildCacheUtils.cloneList(adSetKeys));
        adCampaignGroupLevel.setAdCampGroupKey(adCampGroupKey);
    }

    /**
     * 生成adset
     */
    private void generateAdSetLevel(AdSetLevel adSetLevel, List<AdCreativeLevel> adCreativeLevels, PublishCache cache, EntrustAccountParam account, Set<String> adCountryKeys,
                                        Set<String> adGenderKeys, Set<String> adAgeKeys, List<String> adGroupKeys,
                                        BidInfoVoParam bidInfo, String cBidType, String targetJson,
                                        DateModel endTimeDateModel, DateModel startTimeDateModel, String adSetKey,
                                        Set<String> locationKeys, int adSetIndex, int adCampaignIndex) throws AdsetLimitException {
        String promotedObject;
        if (CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
            promotedObject= "{'application_id' : " + cache.getConnectionObject().getFbConnectionObjectId() + ", 'object_store_url' : '" + cache.getWAdLink() + "'}";
        }else {
            promotedObject= "{'application_id' : " + cache.getConnectionObject().getFbConnectionObjectId() + ", 'object_store_url' : '" + cache.getProductConfiguration().getObjectStoreUrl() + "'}";
        }
        String name = buildAdName(cache, adCreativeLevels, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, adSetIndex, adCampaignIndex, "adSet");
        adSetLevel.setUserId(cache.getUserId());
        adSetLevel.setName(name);
        //modify by sisi for 出价预算优化  预算绑定在出价类型上
        adSetLevel.setDailyBudget(bidInfo.getDailyBudget());
        adSetLevel.setLifetimeBudget(bidInfo.getLifetimeBudget());

        adSetLevel.setStartTimeString(startTimeDateModel.getToTimeString());
        adSetLevel.setStartTime(startTimeDateModel.getDate());
        adSetLevel.setStartUTCTime(startTimeDateModel.getUtcTime());
        if (null != endTimeDateModel) {
            adSetLevel.setEndTimeString(endTimeDateModel.getToTimeString());
            adSetLevel.setEndTime(endTimeDateModel.getDate());
            adSetLevel.setEndUTCTime(endTimeDateModel.getUtcTime());
        }
        adSetLevel.setCampaignStatus(Status.ACTIVE.getMessageCode());
        adSetLevel.setTargeting(targetJson);
        if (!CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
            adSetLevel.setPromotedObject(promotedObject);
        }

        adSetLevel.setCreateTime(cache.getCreateTime());
        adSetLevel.setCreateUTCTime(cache.getCreateTime().getTime());
        adSetLevel.setUpdateTime(cache.getCreateTime());
        adSetLevel.setUpdateUTCTime(cache.getCreateTime().getTime());
        adSetLevel.setAccessToken(account.getAccessToken());
        adSetLevel.setActAccountId(account.getAccountId());
        adSetLevel.setFbConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());
        adSetLevel.setFbConnectionObjectName(cache.getConnectionObject().getName());
        adSetLevel.setPublishBatchId(cache.getPublishBatchId());
        adSetLevel.setPublishBatchName(cache.getPublishBatchFinishName());
        adSetLevel.setProductConfigurationId(cache.getProductConfiguration().getId());
        adSetLevel.setConfiguration(cache.getProductConfiguration().getPlatform());
        adSetLevel.setTimeZone(account.getTimeZone());
        adSetLevel.setPublishResultId(account.getResultId());
        adSetLevel.setAdSetKey(adSetKey);
        adSetLevel.setStatus(PublishStatus.WAIT_PUPLISH.getCode());
        adSetLevel.setAdGroupBatchIndexs(BuildCacheUtils.cloneList(adGroupKeys));
        adSetLevel.setOptimizationGoal(bidInfo.getOptimizationGoal());
        adSetLevel.setBillingEvent(bidInfo.getBillingEvent());
        adSetLevel.setIsAutobid(bidInfo.getIsAutoBid());
        adSetLevel.setBidAmount(bidInfo.getBidAmount());
    }

    /**
     * 生成adgroup
     */
    private void generateAdGroupLevel(AdCreativeLevel adCreativeLevel, Set<String> adCountryKeys, Set<String> locationKeys,
                                            Set<String> adGenderKeys, Set<String> adAgeKeys, String cBidType,
                                            AdGroupLevel adGroupLevel, PublishCache cache,
                                            EntrustAccountParam account, String targetJson, int adGroupIndex, int adCampaignIndex, int adSetIndex, String adGroupKey) throws AdsetLimitException {
        adGroupLevel.setUserId(cache.getUserId());
//        adGroupLevel.setBidInfo(bidInfoStr);
        //conversion_specs is deprecated for versions v2.4
        //adGroupLevel.setConversionSpecs(conversionSpace);
//        adGroupLevel.setBidType(bidType);
        //adGroupLevel.setCreative("{'creative_id':" + creative.getId() + CommonConstants.JSON_END_SYMBOL);
        adGroupLevel.setTargeting(targetJson);
        String name = buildAdGroupName(adCreativeLevel, cache, adCountryKeys, locationKeys, adGenderKeys, adAgeKeys, cBidType, adGroupIndex, adCampaignIndex, adSetIndex);

        adGroupLevel.setName(name);
        //Ivanka提出这一批次所有广告都是应用名称,经测试不能创建广告
        //AdCampNameCustomHelper.replaceConnectionObjectName(cache.getConnectionObject().getName(), "'+|-+|:+|\\s+", "_");
        adGroupLevel.setLocale("zh_CN");
        adGroupLevel.setAdgroupStatus(Status.ACTIVE.getMessageCode());
        //v2.3 objective 设置到了campaign上
        //adGroupLevel.setObjective(AdObjective.MOBILE_APP_INSTALLS.getType());

        adGroupLevel.setCreateTime(cache.getCreateTime());
        adGroupLevel.setCreateUTCTime(cache.getCreateTime().getTime());
        adGroupLevel.setUpdateTime(cache.getCreateTime());
        adGroupLevel.setUpdateUTCTime(cache.getCreateTime().getTime());
        adGroupLevel.setAccessToken(account.getAccessToken());
        adGroupLevel.setActAccountId(account.getAccountId());
        adGroupLevel.setFbConnectionObjectId(cache.getConnectionObject().getFbConnectionObjectId());
        adGroupLevel.setFbConnectionObjectName(cache.getConnectionObject().getName());
        adGroupLevel.setPublishBatchId(cache.getPublishBatchId());
        adGroupLevel.setPublishBatchName(cache.getPublishBatchFinishName());
        adGroupLevel.setProductConfigurationId(cache.getProductConfiguration().getId());
        adGroupLevel.setConfiguration(cache.getProductConfiguration().getPlatform());
        adGroupLevel.setTimeZone(account.getTimeZone());
        adGroupLevel.setPublishResultId(account.getResultId());
        adGroupLevel.setAdCreativeBatchIndex(adCreativeLevel.getKeyForPublishAd());
        adGroupLevel.setAdGroupKey(adGroupKey);
        adGroupLevel.setStatus(PublishStatus.WAIT_PUPLISH.getCode());
        adGroupLevel.setProductType(cache.getConnectionObject().getProductType());
    }


    private String getLocalLocation(Set<String> sets, String line) {
        boolean isFirst = true;
        StringBuffer sb = new StringBuffer();
        Iterator<String> it = sets.iterator();
        while (it.hasNext()) {
            if (!isFirst) {
                sb.append(line);
            }
            sb.append(it.next());
            isFirst = false;
        }
        return sb.toString();
    }


    public String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    private void buildWAdLink(PublishCache cache) {
//        //构造跳转链接
//        String href;
//        if (CommonConstants.OUTLINK.equals(cache.getConnectionObject().getProductType())) {
//            Map<Integer, String> defineKey = new HashMap<>();
//            defineKey.put(TagForBuildnameType.COUNTRY.getIndex(), "_COUNTRY_");
//            defineKey.put(TagForBuildnameType.AGE.getIndex(), "_AGE_");
//            defineKey.put(TagForBuildnameType.GENDER.getIndex(), "_GENDER_");
//            defineKey.put(TagForBuildnameType.PLATFORM.getIndex(), cache.getProductConfiguration().getPlatform());
//            String prefix = cache.getWAdLink(); //目前是 “”
//            StringBuffer sb = new StringBuffer(prefix);
//            List<NameAssembly> tagSeq = cache.getWAdTagSeq();
//            if (ListUtil.isNotEmpty(tagSeq)) {
//                for (NameAssembly every : tagSeq) {
//                    if (StringUtil.isNotEmpty(every.getType()) && "tag".equals(every.getType())) {
//                        String tagValue = defineKey.get(every.getTag());
//                        if (StringUtils.isNotEmpty(tagValue)) {
//                            sb.append(tagValue);
//                        }
//                    } else if (StringUtil.isNotEmpty(every.getType()) && "text".equals(every.getType())) {
//                        sb.append(every.getText());
//                    }
//                }
//            }
//            String link = sb.toString();
//            if (link.lastIndexOf("?") == -1) {
//                sb.append("?sub8=_adGroupId_"); //// TODO: 2016/1/7  to configuration
//            } else if (link.endsWith("?")) {
//                sb.append("sub8=_adGroupId_");
//            } else {
//                sb.append("&sub8=_adGroupId_");
//            }
//            link=sb.toString();
//            //按需追加http://
//            if (!link.startsWith("http://")) {
//                link="http://"+link;
//            }
//            cache.setWAdLink(link);
//            href = link;
//        } else {
//            href = cache.getProductConfiguration().getObjectStoreUrl();
//        }
//        cache.setLink(href);
    }

    /**
     * 生成创意这一步 正交数
     */
    private int buildCreativeCnt(PublishCache cache) {
        int creativeCnt;
        switch (cache.getChooseType()) {
            case IMG:  //图片广告
                int a = 0;
                for (AdImageVoParam adImageVoParam : cache.getAdImages())
                    a += adImageVoParam.getCount();
                creativeCnt = cache.getAdWords().size() * a;
                break;
            case VIDEO:  //视频广告
                int b = 0;
                for (AdVideoVoParam adVideoVoParam :  cache.getAdVideos()) {
                    for (AdImageVoParam adImageVoParam : adVideoVoParam.getAdImages())
                        b += adImageVoParam.getCount();
                }
                creativeCnt = cache.getAdWords().size() * b;
                break;
            case CAROUSEL: //轮播广告
                creativeCnt = cache.getAdWords().size() * cache.getAdImagesGroup().size();
                break;
            default:
                creativeCnt = 0;
        }
        return creativeCnt;
    }

    /**
     * 构建广告名称
     */
    private String buildAdGroupName(AdCreativeLevel adCreativeLevel, PublishCache cache,
                                    Set<String> adCountryKeys, Set<String> locationKeys,
                                    Set<String> adGenderKeys, Set<String> adAgeKeys, String cBidType,
                                    int adGroupIndex, int adCampaignIndex, int adSetIndex) throws AdsetLimitException {
//        String line = "_";
//        StringBuffer adName = new StringBuffer();
//        String celltype = "";
//        String picturename = "";
//        //如果输入的名称不包含素材名称  不去耗时查询素材名称
//        boolean flag = false;
//        List seqList = new ArrayList();
//        for (NameAssembly every : cache.getAdGroupSeq()) {
//            if (StringUtil.isNotEmpty(every.getType()) && "tag".equals(every.getType())) {
//                seqList.add(every.getTag());
//            }
//        }
//        if (ListUtil.isNotEmpty(seqList) && seqList.contains(TagForBuildnameType.picture_name.getKey())) {
//            flag = true;
//        }
//
//        switch (cache.getChooseType()) {
//            case IMG:
////                celltype = IMG.getType();
//                celltype = "banner";
//                if (adCreativeLevel != null && flag) {
//                    picturename = adCreativeLevel.getObjectStorySpec().getLinkData().getPictureName();
//                }
//                break;
//            case VIDEO:
//                celltype = VIDEO.getType();
//                if (adCreativeLevel != null && flag) {
//                    picturename = adCreativeLevel.getObjectStorySpec().getVideoData().getPictureName();
//                }
//                break;
//            case CAROUSEL:
//                celltype = CAROUSEL.getType();
//                if (adCreativeLevel != null && flag) {
//                    List<ChildAttachments> childAttachmentses = adCreativeLevel.getObjectStorySpec().getLinkData().getChildAttachmentses();
//                    List<String> ll = new ArrayList<>();
//                    for (ChildAttachments childAttachmentse : childAttachmentses) {
//                        ll.add(getFileNameNoEx(childAttachmentse.getImgName()));
//                    }
////                    picturename = adCreativeLevel.getObjectStorySpec().getLinkData().getName();
//                    picturename = Joiner.on(line).join(ll);
//                }
//                break;
//        }
//        Map<Integer, String> defineKey = new HashMap<>();
//        defineKey.put(TagForBuildnameType.COUNTRY.getIndex(), getLocalLocation(adCountryKeys, line));
//        defineKey.put(TagForBuildnameType.APPNAME.getIndex(), ConversionUtils.replaceConnectionObjectName(cache.getConnectionObject().getName(), "'+|-+|:+|\\s+", line));
//        defineKey.put(TagForBuildnameType.GENDER.getIndex(), getLocalLocation(adGenderKeys, line));
//        defineKey.put(TagForBuildnameType.AGE.getIndex(), getLocalLocation(adAgeKeys, line));
//        defineKey.put(TagForBuildnameType.PLATFORM.getIndex(), cache.getProductConfiguration().getPlatform());
//        defineKey.put(TagForBuildnameType.BIDTYPE.getIndex(), cBidType);
//        defineKey.put(TagForBuildnameType.DATE.getIndex(), cache.getServerDate().substring(cache.getServerDate().length() - 4, cache.getServerDate().length()));
//        defineKey.put(TagForBuildnameType.CELLTYPE.getIndex(), celltype);
//        defineKey.put(TagForBuildnameType.PICTURENAME.getIndex(), getFileNameNoEx(picturename));
//        defineKey.put(TagForBuildnameType.CREATOR.getIndex(), cache.getNickName());
//        defineKey.put(TagForBuildnameType.APPSIMPLENAME.getIndex(), cache.getAdPublishConditionDetailCache().getConnObjSimpleName());
//        defineKey.put(TagForBuildnameType.PRICE.getIndex(), getPrice(locationKeys, cache.getAdPublishConditionDetailCache()));
//        defineKey.put(TagForBuildnameType.UNIQUE.getIndex(), buildUnique(adGroupIndex, adCampaignIndex, adSetIndex, cache.getPublishBatchId(), cache.getTimeZone()));
//        String shortDate = DateUtil.dateToString(new Date(), DateUtil.FORMAT_THREE).substring(4, 8);
//        defineKey.put(TagForBuildnameType.SHORTDATE.getIndex(), shortDate);
//        defineKey.put(TagForBuildnameType.SHOTSEQ.getIndex(), buildUserDaySeq(adCreativeLevel.getUserId()+shortDate));
//
//
//        for (NameAssembly every : cache.getAdGroupSeq()) {
//            adNameAppend(line, defineKey, adName, every);
//        }
//        if (StringUtil.isEmpty(adName.toString()) || line.equals(adName.toString())) {
//            return cache.getAdTitle() + line + adGroupIndex;
//        } else {
//            String returns = StringUtil.trimFirstAndLastChar(adName.toString().toLowerCase(), line.charAt(0));
//            try{
//                if (returns.getBytes("utf-8").length > 400) {
//                    throw new AdsetLimitException(ErrorCode.ERROR_60021);
//                }
//            }
//            catch (UnsupportedEncodingException e)
//            {
//                logger.error("生成广告命名异常：", e);
//            }
//            return returns.replaceAll(line + "+", line);
//        }
        return "";
    }

    private String buildUserDaySeq(String userId) {
        return  redisClient.getUserDaySeq(userId).toString();
    }

    private String getPrice(Set<String> locationKeys, AdPublishConditionDetailCache adPublishConditionDetailCache) {
        if (null == adPublishConditionDetailCache || null == adPublishConditionDetailCache.getRegionAndPrices()){
            return "";
        }

        String regionType = adPublishConditionDetailCache.getRegionType();
        if ("global".equals(regionType)){
            //如果是全球就获取全球的价格
            return formatPrice(adPublishConditionDetailCache.getRegionAndPrices().getGlobal().getPrice());
        } else {
            //如果投放控制处设置的是指定地区
            return specifiedAreaPrice(locationKeys, adPublishConditionDetailCache.getRegionAndPrices().getInclude());
        }
    }

    private String buildUnique(int adGroupIndex, int adCampaignIndex, int adSetIndex, Long batchId, String timeZone)
    {
        return  TenTo36.baseString(batchId) + String.format("%3s", TenTo36.baseString(adCampaignIndex)).replaceAll("\\s", "0") + String.format("%1s", TenTo36.baseString(adSetIndex)) + TenTo36.baseString(adGroupIndex);
    }

    private String specifiedAreaPrice(Set<String> locationKeys, List<RegionAndPriceBo> includes) {
        if (CollectionUtils.isEmpty(includes)){
            return "";
        }

        Double finalPrice = null;
        boolean isFirst = true;
        for (RegionAndPriceBo regionAndPriceBo : includes){
            //遍历每一组地区
            //判断用户定位中的地区是否在当前出价组中
            List<RegionBo> regions = regionAndPriceBo.getRegion();
            boolean isIn = false;
            for (RegionBo region : regions){
                if (locationKeys.contains(region.getKey())){
                    isIn = true;
                    break;
                }
            }

            if (isIn){
                Double currentPrice = regionAndPriceBo.getPrice();
                if (isFirst){
                    finalPrice = currentPrice;
                } else {
                    //若是投放的国家组单价不一样（混合投放），则显示最低的单价价格
                    if (0 < Double.compare(finalPrice, currentPrice)){
                        finalPrice = currentPrice;
                    }
                }
                isFirst = false;
            }
        }

        return formatPrice(finalPrice);
    }

    private String formatPrice(Double price){
        if (null == price){
            return "";
        }

        DecimalFormat df = new DecimalFormat("0.00");
        return df.format(price);
    }

    /**
     * 构建营销活动和广告组名称
     */
    private String buildAdName(PublishCache cache, List<AdCreativeLevel> adCreativeLevels,
                               Set<String> adCountryKeys, Set<String> locationKeys, Set<String> adGenderKeys,
                               Set<String> adAgeKeys, String cBidType, int adSetIndex, int adCampaignIndex, String type) throws AdsetLimitException {
//        String line = "_";
//        String countryDescription = getLocalLocation(adCountryKeys, line);
//        String genderDescription = getLocalLocation(adGenderKeys, line);
//        String ageDescription = getLocalLocation(adAgeKeys, line);
//
//        String celltype = "";
////        StringBuffer picturename = new StringBuffer();
//        //如果输入的名称不包含素材名称  不去耗时查询素材名称
//        boolean flag = false;
//        //唯一编号
//        String unique = "";
//        List seqList = new ArrayList();
//        List<NameAssembly> seq = cache.getAdCampSeq();
//        if ("adCampaignGroup".equals(type)) {
//            seq = cache.getAdCampSeq();
//            unique = TenTo36.baseString(cache.getPublishBatchId()) + String.format("%3s", TenTo36.baseString(adCampaignIndex)).replaceAll("\\s", "0");
//        } else if ("adSet".equals(type)) {
//            seq = cache.getAdSetSeq();
//            unique = TenTo36.baseString(cache.getPublishBatchId()) + String.format("%3s", TenTo36.baseString(adCampaignIndex)).replaceAll("\\s", "0") + String.format("%1s", TenTo36.baseString(adSetIndex));
//        }
//
//        for (NameAssembly every : seq) {
//            if (StringUtil.isNotEmpty(every.getType()) && "tag".equals(every.getType())) {
//                seqList.add(every.getTag());
//            }
//        }
//
//        if (ListUtil.isNotEmpty(seqList) && seqList.contains(TagForBuildnameType.picture_name.getKey())) {
//            flag = true;
//        }
//
//
//        Set<String> resourceNameList = new HashSet<>();
//        switch (cache.getChooseType()) {
//            case IMG:
//                celltype = "banner";
//                if (ListUtil.isNotEmpty(adCreativeLevels) && flag) {
//                    for (AdCreativeLevel adCreativeLevel : adCreativeLevels) {
//                        String fileName = adCreativeLevel.getObjectStorySpec().getLinkData().getPictureName();
//                        resourceNameList.add(getFileNameNoEx(fileName));
//                    }
//                }
//                break;
//            case VIDEO:
//                celltype = VIDEO.getType();
//                if (ListUtil.isNotEmpty(adCreativeLevels) && flag) {
//                    for (AdCreativeLevel adCreativeLevel : adCreativeLevels) {
//                        String fileName = adCreativeLevel.getObjectStorySpec().getVideoData().getPictureName();
//                        resourceNameList.add(getFileNameNoEx(fileName));
//                    }
//                }
//                break;
//            case CAROUSEL:
//                celltype = CAROUSEL.getType();
//                if (ListUtil.isNotEmpty(adCreativeLevels) && flag)
//                    for (AdCreativeLevel adCreativeLevel : adCreativeLevels) {
//                        List<ChildAttachments> childAttachmentses = adCreativeLevel.getObjectStorySpec().getLinkData().getChildAttachmentses();
//                        for (ChildAttachments childAttachmentse : childAttachmentses) {
//                            String fileName = childAttachmentse.getImgName();
//                            resourceNameList.add(getFileNameNoEx(fileName));
//                        }
//                    }
//                break;
//        }
//        String picturename = Joiner.on(line).join(resourceNameList);
//        Map<Integer, String> defineKey = new HashMap<>();
//        defineKey.put(TagForBuildnameType.COUNTRY.getIndex(), countryDescription);
//        defineKey.put(TagForBuildnameType.APPNAME.getIndex(), ConversionUtils.replaceConnectionObjectName(cache.getConnectionObject().getName(), "'+|-+|:+|\\s+", line));
//        defineKey.put(TagForBuildnameType.GENDER.getIndex(), genderDescription);
//        defineKey.put(TagForBuildnameType.AGE.getIndex(), ageDescription);
//        defineKey.put(TagForBuildnameType.PLATFORM.getIndex(), cache.getProductConfiguration().getPlatform());
//        defineKey.put(TagForBuildnameType.BIDTYPE.getIndex(), cBidType);
//        defineKey.put(TagForBuildnameType.DATE.getIndex(), cache.getServerDate().substring(cache.getServerDate().length() - 4, cache.getServerDate().length()));
//        defineKey.put(TagForBuildnameType.CELLTYPE.getIndex(), celltype);
//        defineKey.put(TagForBuildnameType.PICTURENAME.getIndex(), picturename.toString());
//        defineKey.put(TagForBuildnameType.CREATOR.getIndex(), cache.getNickName());
//        defineKey.put(TagForBuildnameType.APPSIMPLENAME.getIndex(), cache.getAdPublishConditionDetailCache().getConnObjSimpleName());
//        defineKey.put(TagForBuildnameType.PRICE.getIndex(), getPrice(locationKeys, cache.getAdPublishConditionDetailCache()));
//        defineKey.put(TagForBuildnameType.UNIQUE.getIndex(), unique);
//
//
//        StringBuffer adName = new StringBuffer();
//        for (NameAssembly every : seq) {
//            adNameAppend(line, defineKey, adName, every);
//        }
//
//        if (StringUtil.isEmpty(adName.toString()) || line.equals(adName.toString())) {
//            return cache.getAdTitle();
//        } else {
//            String returns = StringUtil.trimFirstAndLastChar(adName.toString().toLowerCase(), line.charAt(0));
//            try{
//                if (returns.getBytes("utf-8").length > 400) {
//                    throw new AdsetLimitException(ErrorCode.ERROR_60022,type);
//                }
//            }
//            catch (UnsupportedEncodingException e)
//            {
//                logger.error("生成"+type+"命名异常：", e);
//            }
//            return returns.replaceAll(line + "+", line);
//        }
        return "";
    }

    private void adNameAppend(String line, Map<Integer, String> defineKey, StringBuffer adName, NameAssembly every) {
        String tagValue;
        if (StringUtil.isNotEmpty(every.getType()) && "tag".equals(every.getType())) {
            tagValue = defineKey.get(every.getTag());
            if (StringUtils.isNotEmpty(tagValue)){
                adName.append(tagValue + line);
            }
        } else if (StringUtil.isNotEmpty(every.getType()) && "text".equals(every.getType())) {
            adName.append(every.getText() + line);
        }
    }

    private Set<String> buildCountryDescription(LocalLocation localLocation) {
        Set<String> sets = new LinkedHashSet<>();
        if (null != localLocation) {
            List<Country> countries = localLocation.getCountries();
            if (ListUtil.isNotEmpty(countries)) {
                for (Country country : countries) {
                    sets.add(country.getCountryCode());
                }
            }
        }
        return sets;
    }

    /**
     * @param localGender localGender
     * @return String
     * @discription 根据Gender获取描述
     * @author Administrator
     * 创建时间 2014年6月10日 下午12:09:35
     */
    @SuppressWarnings("unchecked")
    private Set<String> buildGenderDescription(LocalGender localGender) {
        Set<String> sets = new LinkedHashSet<>();
        if (null == localGender || ListUtil.isEmpty(localGender.getGenders())) {
            sets.add("F");
            sets.add("M");
        } else {
            List<Integer> genders = localGender.getGenders();
            int gendersCount = genders.size() - 1;
            Integer gender;
            for (int i = 0; i <= gendersCount; i++) {
                gender = genders.get(i);
                if (Gender.male.getCode() == gender) {
                    sets.add("M");
                } else if(Gender.all.getCode() == gender) {
                    sets.add("F");
                    sets.add("M");
                } else {
                    sets.add("F");
                }
            }
        }
        return sets;
    }

    /**
     * @param age age
     * @return String
     * @discription 根据年龄获取描述
     * @author Administrator
     * 创建时间 2014年6月10日 下午12:05:11
     */
    private Set<String> buildAgeDescription(Age age) {
        Set<String> sets = new LinkedHashSet<>();
        if (age != null && null != age.getAgeMin()) {
            sets.add(age.getAgeMin().toString());
        }
        if (age != null && null != age.getAgeMax()) {
            sets.add(age.getAgeMax().toString());
        }
        return sets;
    }
}

